package com.suray.system.run.seer.task;

import com.suray.basic.wcs.path.core.Node;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.commin.core.utils.SpringContextHolder;
import com.suray.commin.core.utils.StringUtils;
import com.suray.system.run.seer.http.ToSeerAgv;
import com.suray.system.run.seer.http.bean.SeerAgvTaskInquire;
import com.suray.system.run.seer.mysql.*;
import com.suray.system.run.seer.type.SeerAgvOperation;
import com.suray.system.run.seer.type.SeerAgvProcess;
import com.suray.system.run.seer.util.PointManage;
import com.suray.wcs.service.core.util.LockNodeManager;
import com.suray.wcs.service.test.base.BaseThread;
import com.suray.wcs.service.util.WcsUtil;

import java.util.*;

public class SeerAgvTaskImpl implements SeerAgvTask {
    private SeerTaskDBServiceImpl seerTaskDBService = SpringContextHolder.getBean(SeerTaskDBServiceImpl.class);

    private static int taskSeed = 0;

    private volatile List<SeerTaskAction> tasks;

    public SeerAgvTaskImpl() {
        tasks = new ArrayList<>();
    }

    public boolean generalAgvTransTask(String startPoint, String endPoint, String barcode) {
        String taskId = generalAgvTaskId();

        SeerTaskDB seerTaskDB = new SeerTaskDB(
                taskId, startPoint, PointManage.findOutPoint(startPoint),
                endPoint, PointManage.findOutPoint(endPoint), barcode,
                SeerAgvOperation.JACK_LOAD.getAction(), SeerAgvOperation.JACK_UNLOAD.getAction());

        if (seerTaskDBService.save(seerTaskDB)) {
            LoggerUtil.info("插入Agv任务：" + seerTaskDB, this.getClass());
            seerTaskDBService.save(seerTaskDB);
            return addTask(seerTaskDB);
        }

        return false;
    }

    public boolean generalAgvTransTask(String startPoint, String endPoint) {
        String taskId = generalAgvTaskId();

        SeerTaskDB seerTaskDB = new SeerTaskDB(
                taskId, startPoint, PointManage.findOutPoint(startPoint),
                endPoint, PointManage.findOutPoint(endPoint), null,
                SeerAgvOperation.JACK_LOAD.getAction(), SeerAgvOperation.JACK_UNLOAD.getAction());

        if (seerTaskDBService.save(seerTaskDB)) {
            LoggerUtil.info("插入Agv任务：" + seerTaskDB, this.getClass());
            seerTaskDBService.save(seerTaskDB);
            return addTask(seerTaskDB);
        }

        return false;
    }

    @Override
    public boolean lockPoints(Set<String> points, Object obj) {
        return false;
    }

    @Override
    public boolean releasePoints(Set<String> points, Object obj) {
        return false;
    }

    @Override
    public int checkLockPoints(Set<String> points, Object obj) {
        return 0;
    }

    /**
     * 添加任务
     * @param seerTaskDB
     * @return
     */
    private boolean addTask(SeerTaskDB seerTaskDB) {
        return tasks.add(new SeerTaskAction(seerTaskDB));
    }

    /**
     * 删除任务
     * @param task
     * @return
     */
    private boolean removeTask(SeerTaskAction task) {
        if (task.isEnd()) {
            return tasks.remove(task);
        }

        LoggerUtil.error("任务未结束不能清除：" + task, this.getClass());

        return false;
    }

    /**
     * 生成Agv任务id
     * @return
     */
    private String generalAgvTaskId() {
        taskSeed++;
        return "" + taskSeed;
    }

    public void init() {
        List<SeerTaskDB> seerTaskDBS = seerTaskDBService.findUnFinishTask();

        seerTaskDBS.forEach(seerTaskDB -> {
            try {
                addTask(seerTaskDB);
            } catch (Exception e) {
                WcsUtil.exceptionLog(e, this.getClass());
            }
        });

        checkTaskPoint();

        new SeerAgvTaskCheck(this).start();
    }

    /**
     * 检测点位是否需要加锁
     */
    private void checkTaskPoint() {
        PointManage.getAllPointMapDBCloseRgv().forEach(pointMapDB -> {
            try {
                String lockTaskId = pointMapDB.getLockObj();
                if (StringUtils.isNotEmpty(lockTaskId)) {
                    SeerTaskAction task = findSeerTaskByTaskId(lockTaskId);
                    if (task != null) {
                        LockNodeManager.lockedNodes(Collections.singleton(Node.parseGrid(pointMapDB.getMapNode())), task);
                    } else {
                        LockNodeManager.lockedNodes(Collections.singleton(Node.parseGrid(pointMapDB.getMapNode())), lockTaskId);
                        LoggerUtil.info("锁定点位的任务不存在, 请确认点位没有AGV后手动清除点位:" + pointMapDB, this.getClass());
                        WcsUtil.notification("锁定点位的任务不存在, 请确认点位没有AGV后手动清除点位:" + pointMapDB);
                    }
                }
            } catch (Exception e) {
                WcsUtil.exceptionLog(e, this.getClass());
                LoggerUtil.info("点位锁定失败:" + pointMapDB, this.getClass());
            }
        });
    }

    private SeerTaskAction findSeerTaskByTaskId(String taskId) {
        for (SeerTaskAction task : tasks) {
            if (task.getTaskDB().getTaskId().equals(taskId)) {
                return task;
            }
        }

        return null;
    }

    public void run() {
        List<SeerTaskAction> endTasks = new ArrayList<>();
        tasks.forEach(task -> {
            try {
                task.run();

                if (task.isEnd()) {
                    endTasks.add(task);
                }
            } catch (Exception e) {
                WcsUtil.exceptionLog(e, this.getClass());
            }
        });

        endTasks.forEach(task -> {
            try {
                if (!removeTask(task)) {
                    LoggerUtil.warn("Seer Agv 任务清除失败:" + task, this.getClass());
                }
            } catch (Exception e) {
                WcsUtil.exceptionLog(e, this.getClass());
            }
        });
    }

    class SeerAgvTaskCheck extends BaseThread {

        private SeerAgvTaskImpl seerAgvTask;

        SeerAgvTaskCheck(SeerAgvTaskImpl seerAgvTask) {
            super("Seer Agv任务查询", 2000);

            this.seerAgvTask = seerAgvTask;
        }

        @Override
        protected void process() {
            seerAgvTask.tasks.forEach(task -> {
                try {
                    SeerTaskDB taskDB = task.getTaskDB();

                    if (taskDB.getProcess().getValue() > SeerAgvProcess.SEND_TASK.getValue()
                            && taskDB.getProcess().getValue() < SeerAgvProcess.END.getValue()) {
                        //任务已经发送，且任务未结束则持续查询任务状态
                        SeerAgvTaskInquire taskInquire = inquireTask(taskDB);
                        task.setTaskInquire(taskInquire);
                    }
                } catch (Exception e) {
                    WcsUtil.exceptionLog(e, this.getClass());
                }
            });
        }

        private SeerAgvTaskInquire inquireTask(SeerTaskDB taskDB) {
            return ToSeerAgv.inquireTask(taskDB.getTaskId());
        }
    }
}
